package main

import (
	"database/sql"
	"encoding/json"
	"reflect"

	"test.com/fusion"
	"test.com/worlddb"
)

type lootDialogTableRow struct {
	LsID   uint32 `json:"lsID"`
	LsName string `json:"lsName"`
}

func getAllLoot4DialogTable(db *sql.DB) ([]*lootDialogTableRow, error) {
	var lsRows []*lootDialogTableRow
	rows, err := db.Query("SELECT `lsID`,`lsName` FROM `loot_set`")
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	for rows.Next() {
		var lsRow lootDialogTableRow
		if err := rows.Scan(&lsRow.LsID, &lsRow.LsName); err == nil {
			lsRows = append(lsRows, &lsRow)
		} else {
			return nil, err
		}
	}
	return lsRows, nil
}

func getAllLootNames(db *sql.DB) (map[uint32]string, error) {
	lsRows, err := getAllLoot4DialogTable(db)
	if err != nil {
		return nil, err
	}
	lsNames := map[uint32]string{}
	for _, lsRow := range lsRows {
		lsNames[lsRow.LsID] = lsRow.LsName
	}
	return lsNames, nil
}

func getLootSetInfo(db *sql.DB, lsID uint32) (*worlddb.LootSet, error) {
	var lsInfo *worlddb.LootSet
	lsInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsInfo), "`lsID`=?", lsID)
	if err != nil {
		return nil, err
	}
	if lsInfoVals.Len() < 1 {
		return nil, sql.ErrNoRows
	}
	return lsInfoVals.Index(0).Interface().(*worlddb.LootSet), nil
}

func getLootSetGroupIndexes(db *sql.DB, lsID uint32) ([]*worlddb.LootSetGroup, error) {
	var lsgInfo *worlddb.LootSetGroup
	lsgInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsgInfo), "`lsID`=?", lsID)
	if err != nil {
		return nil, err
	}
	return lsgInfoVals.Interface().([]*worlddb.LootSetGroup), nil
}

func getLootSetGroupInfo(db *sql.DB, lsgID uint32) (*worlddb.LootSetGroup, error) {
	var lsgInfo *worlddb.LootSetGroup
	lsgInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsgInfo), "`lsgID`=?", lsgID)
	if err != nil {
		return nil, err
	}
	if lsgInfoVals.Len() < 1 {
		return nil, sql.ErrNoRows
	}
	return lsgInfoVals.Index(0).Interface().(*worlddb.LootSetGroup), nil
}

func getLootSetGroupItemIndexes(db *sql.DB, lsgID uint32) ([]*worlddb.LootSetGroupItem, error) {
	var lsgiInfo *worlddb.LootSetGroupItem
	lsgiInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsgiInfo), "`lsgID`=?", lsgID)
	if err != nil {
		return nil, err
	}
	return lsgiInfoVals.Interface().([]*worlddb.LootSetGroupItem), nil
}

func getLootSetGroupItemInfo(db *sql.DB, lsgiID uint32) (*worlddb.LootSetGroupItem, error) {
	var lsgiInfo *worlddb.LootSetGroupItem
	lsgiInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsgiInfo), "`lsgiID`=?", lsgiID)
	if err != nil {
		return nil, err
	}
	if lsgiInfoVals.Len() < 1 {
		return nil, sql.ErrNoRows
	}
	return lsgiInfoVals.Index(0).Interface().(*worlddb.LootSetGroupItem), nil
}

func getLootSetGroupChequeIndexes(db *sql.DB, lsgID uint32) ([]*worlddb.LootSetGroupCheque, error) {
	var lsgcInfo *worlddb.LootSetGroupCheque
	lsgcInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsgcInfo), "`lsgID`=?", lsgID)
	if err != nil {
		return nil, err
	}
	return lsgcInfoVals.Interface().([]*worlddb.LootSetGroupCheque), nil
}

func getLootSetGroupChequeInfo(db *sql.DB, lsgcID uint32) (*worlddb.LootSetGroupCheque, error) {
	var lsgcInfo *worlddb.LootSetGroupCheque
	lsgcInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsgcInfo), "`lsgcID`=?", lsgcID)
	if err != nil {
		return nil, err
	}
	if lsgcInfoVals.Len() < 1 {
		return nil, sql.ErrNoRows
	}
	return lsgcInfoVals.Index(0).Interface().(*worlddb.LootSetGroupCheque), nil
}

func getLootSetInstanceJsonData(db *sql.DB, lsID uint32) ([]byte, error) {
	var err error
	var lsProto lootSetWebPrototype
	lsProto.LsInfo, err = getLootSetInfo(db, lsID)
	if err != nil {
		return nil, err
	}
	lsProto.LsgIndexes, err = getLootSetGroupIndexes(
		db, lsProto.LsInfo.LsID)
	if err != nil {
		return nil, err
	}
	if len(lsProto.LsgIndexes) > 0 {
		lsProto.LsgInfo, err = getLootSetGroupInfo(
			db, lsProto.LsgIndexes[0].LsgID)
		if err != nil {
			return nil, err
		}
		lsProto.LsgiIndexes, err = getLootSetGroupItemIndexes(
			db, lsProto.LsgInfo.LsgID)
		if err != nil {
			return nil, err
		}
		lsProto.LsgcIndexes, err = getLootSetGroupChequeIndexes(
			db, lsProto.LsgInfo.LsgID)
		if err != nil {
			return nil, err
		}
	} else {
		lsProto.LsgInfo = &worlddb.LootSetGroup{}
	}
	if len(lsProto.LsgiIndexes) > 0 {
		lsProto.LsgiInfo, err = getLootSetGroupItemInfo(
			db, lsProto.LsgiIndexes[0].LsgiID)
		if err != nil {
			return nil, err
		}
	} else {
		lsProto.LsgiInfo = &worlddb.LootSetGroupItem{}
	}
	if len(lsProto.LsgcIndexes) > 0 {
		lsProto.LsgcInfo, err = getLootSetGroupChequeInfo(
			db, lsProto.LsgcIndexes[0].LsgcID)
		if err != nil {
			return nil, err
		}
	} else {
		lsProto.LsgcInfo = &worlddb.LootSetGroupCheque{}
	}
	lsData, err := json.Marshal(
		fusion.MarshalEntityToInterface(&lsProto, "json"))
	if err != nil {
		return nil, err
	}
	return lsData, nil
}

func getLootSetGroupInstanceJsonData(
	db *sql.DB, lsID, lsgID uint32) ([]byte, error) {
	var err error
	var lsgProto lootSetGroupWebPrototype
	lsgProto.LsgIndexes, err = getLootSetGroupIndexes(db, lsID)
	if err != nil {
		return nil, err
	}
	lsgProto.LsgInfo, err = getLootSetGroupInfo(db, lsgID)
	if err != nil {
		return nil, err
	}
	lsgProto.LsgiIndexes, err = getLootSetGroupItemIndexes(
		db, lsgProto.LsgInfo.LsgID)
	if err != nil {
		return nil, err
	}
	lsgProto.LsgcIndexes, err = getLootSetGroupChequeIndexes(
		db, lsgProto.LsgInfo.LsgID)
	if err != nil {
		return nil, err
	}
	if len(lsgProto.LsgiIndexes) > 0 {
		lsgProto.LsgiInfo, err = getLootSetGroupItemInfo(
			db, lsgProto.LsgiIndexes[0].LsgiID)
		if err != nil {
			return nil, err
		}
	} else {
		lsgProto.LsgiInfo = &worlddb.LootSetGroupItem{}
	}
	if len(lsgProto.LsgcIndexes) > 0 {
		lsgProto.LsgcInfo, err = getLootSetGroupChequeInfo(
			db, lsgProto.LsgcIndexes[0].LsgcID)
		if err != nil {
			return nil, err
		}
	} else {
		lsgProto.LsgcInfo = &worlddb.LootSetGroupCheque{}
	}
	lsgData, err := json.Marshal(
		fusion.MarshalEntityToInterface(&lsgProto, "json"))
	if err != nil {
		return nil, err
	}
	return lsgData, nil
}

func getLootSetGroupItemInstanceJsonData(
	db *sql.DB, lsgID, lsgiID uint32) ([]byte, error) {
	var err error
	var lsgiProto lootSetGroupItemWebPrototype
	lsgiProto.LsgiIndexes, err = getLootSetGroupItemIndexes(db, lsgID)
	if err != nil {
		return nil, err
	}
	lsgiProto.LsgiInfo, err = getLootSetGroupItemInfo(db, lsgiID)
	if err != nil {
		return nil, err
	}
	lsgiData, err := json.Marshal(
		fusion.MarshalEntityToInterface(&lsgiProto, "json"))
	if err != nil {
		return nil, err
	}
	return lsgiData, nil
}

func getLootSetGroupChequeInstanceJsonData(
	db *sql.DB, lsgID, lsgcID uint32) ([]byte, error) {
	var err error
	var lsgcProto lootSetGroupChequeWebPrototype
	lsgcProto.LsgcIndexes, err = getLootSetGroupChequeIndexes(db, lsgID)
	if err != nil {
		return nil, err
	}
	lsgcProto.LsgcInfo, err = getLootSetGroupChequeInfo(db, lsgcID)
	if err != nil {
		return nil, err
	}
	lsgcData, err := json.Marshal(
		fusion.MarshalEntityToInterface(&lsgcProto, "json"))
	if err != nil {
		return nil, err
	}
	return lsgcData, nil
}

func newLootSetInstance(tx *sql.Tx, lsName string) (uint32, error) {
	lsInfo := worlddb.LootSet{LsName: lsName}
	lsID, err := fusion.SaveJsontableToDB(tx, &lsInfo)
	if err != nil {
		return 0, err
	}
	lsgInfo := worlddb.LootSetGroup{LsID: lsID}
	lsgID, err := fusion.SaveJsontableToDB(tx, &lsgInfo)
	if err != nil {
		return 0, err
	}
	lsgiInfo := worlddb.LootSetGroupItem{LsID: lsID, LsgID: lsgID}
	_, err = fusion.SaveJsontableToDB(tx, &lsgiInfo)
	if err != nil {
		return 0, err
	}
	lsgcInfo := worlddb.LootSetGroupCheque{LsID: lsID, LsgID: lsgID}
	_, err = fusion.SaveJsontableToDB(tx, &lsgcInfo)
	if err != nil {
		return 0, err
	}
	return lsID, nil
}

func newLootSetGroupInstance(tx *sql.Tx, lsID uint32) (uint32, error) {
	lsgInfo := worlddb.LootSetGroup{LsID: lsID}
	lsgID, err := fusion.SaveJsontableToDB(tx, &lsgInfo)
	if err != nil {
		return 0, err
	}
	lsgiInfo := worlddb.LootSetGroupItem{LsID: lsID, LsgID: lsgID}
	_, err = fusion.SaveJsontableToDB(tx, &lsgiInfo)
	if err != nil {
		return 0, err
	}
	lsgcInfo := worlddb.LootSetGroupCheque{LsID: lsID, LsgID: lsgID}
	_, err = fusion.SaveJsontableToDB(tx, &lsgcInfo)
	if err != nil {
		return 0, err
	}
	return lsgID, nil
}

func newLootSetGroupItemInstance(tx *sql.Tx, lsID, lsgID uint32) (uint32, error) {
	lsgiInfo := worlddb.LootSetGroupItem{LsID: lsID, LsgID: lsgID}
	lsgiID, err := fusion.SaveJsontableToDB(tx, &lsgiInfo)
	if err != nil {
		return 0, err
	}
	return lsgiID, nil
}

func newLootSetGroupChequeInstance(tx *sql.Tx, lsID, lsgID uint32) (uint32, error) {
	lsgcInfo := worlddb.LootSetGroupCheque{LsID: lsID, LsgID: lsgID}
	lsgcID, err := fusion.SaveJsontableToDB(tx, &lsgcInfo)
	if err != nil {
		return 0, err
	}
	return lsgcID, nil
}

func copyLootSetInstance(db *sql.DB, tx *sql.Tx, lsID uint32) (uint32, error) {
	var lsInfo *worlddb.LootSet
	lsInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsInfo), "`lsID`=?", lsID)
	if err != nil {
		return 0, err
	}
	if lsInfoVals.Len() < 1 {
		return 0, sql.ErrNoRows
	}
	lsInfo = lsInfoVals.Index(0).Interface().(*worlddb.LootSet)
	lsInfo.LsID = 0
	ID, err := fusion.SaveJsontableToDB(tx, lsInfo)
	if err != nil {
		return 0, err
	}
	var lsgInfo *worlddb.LootSetGroup
	lsgInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsgInfo), "`lsID`=? ORDER BY `lsgID`", lsID)
	if err != nil {
		return 0, err
	}
	var lsgIDsMap = map[uint32]uint32{}
	for i, n := 0, lsgInfoVals.Len(); i < n; i++ {
		lsgInfo = lsgInfoVals.Index(i).Interface().(*worlddb.LootSetGroup)
		oldLsgID := lsgInfo.LsgID
		lsgInfo.LsID, lsgInfo.LsgID = ID, 0
		newID, err := fusion.SaveJsontableToDB(tx, lsgInfo)
		if err == nil {
			lsgIDsMap[oldLsgID] = newID
		} else {
			return 0, err
		}
	}
	var lsgiInfo *worlddb.LootSetGroupItem
	lsgiInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsgiInfo), "`lsID`=? ORDER BY `lsgiID`", lsID)
	if err != nil {
		return 0, err
	}
	for i, n := 0, lsgiInfoVals.Len(); i < n; i++ {
		lsgiInfo = lsgiInfoVals.Index(i).Interface().(*worlddb.LootSetGroupItem)
		lsgiInfo.LsID, lsgiInfo.LsgiID = ID, 0
		lsgiInfo.LsgID = lsgIDsMap[lsgiInfo.LsgID]
		_, err = fusion.SaveJsontableToDB(tx, lsgiInfo)
		if err != nil {
			return 0, err
		}
	}
	var lsgcInfo *worlddb.LootSetGroupCheque
	lsgcInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsgcInfo), "`lsID`=? ORDER BY `lsgcID`", lsID)
	if err != nil {
		return 0, err
	}
	for i, n := 0, lsgcInfoVals.Len(); i < n; i++ {
		lsgcInfo = lsgcInfoVals.Index(i).Interface().(*worlddb.LootSetGroupCheque)
		lsgcInfo.LsID, lsgcInfo.LsgcID = ID, 0
		lsgcInfo.LsgID = lsgIDsMap[lsgcInfo.LsgID]
		_, err = fusion.SaveJsontableToDB(tx, lsgcInfo)
		if err != nil {
			return 0, err
		}
	}
	return ID, nil
}

func copyLootSetGroupInstance(db *sql.DB, tx *sql.Tx, lsgID uint32) (uint32, error) {
	var lsgInfo *worlddb.LootSetGroup
	lsgInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsgInfo), "`lsgID`=?", lsgID)
	if err != nil {
		return 0, err
	}
	if lsgInfoVals.Len() < 1 {
		return 0, sql.ErrNoRows
	}
	lsgInfo = lsgInfoVals.Index(0).Interface().(*worlddb.LootSetGroup)
	lsgInfo.LsgID = 0
	ID, err := fusion.SaveJsontableToDB(tx, lsgInfo)
	if err != nil {
		return 0, err
	}
	var lsgiInfo *worlddb.LootSetGroupItem
	lsgiInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsgiInfo), "`lsgID`=? ORDER BY `lsgiID`", lsgID)
	if err != nil {
		return 0, err
	}
	for i, n := 0, lsgiInfoVals.Len(); i < n; i++ {
		lsgiInfo = lsgiInfoVals.Index(i).Interface().(*worlddb.LootSetGroupItem)
		lsgiInfo.LsgID, lsgiInfo.LsgiID = ID, 0
		_, err = fusion.SaveJsontableToDB(tx, lsgiInfo)
		if err != nil {
			return 0, err
		}
	}
	var lsgcInfo *worlddb.LootSetGroupCheque
	lsgcInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsgcInfo), "`lsgID`=? ORDER BY `lsgcID`", lsgID)
	if err != nil {
		return 0, err
	}
	for i, n := 0, lsgcInfoVals.Len(); i < n; i++ {
		lsgcInfo = lsgcInfoVals.Index(i).Interface().(*worlddb.LootSetGroupCheque)
		lsgcInfo.LsgID, lsgcInfo.LsgcID = ID, 0
		_, err = fusion.SaveJsontableToDB(tx, lsgcInfo)
		if err != nil {
			return 0, err
		}
	}
	return ID, nil
}

func copyLootSetGroupItemInstance(db *sql.DB, tx *sql.Tx, lsgiID uint32) (uint32, error) {
	var lsgiInfo *worlddb.LootSetGroupItem
	lsgiInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsgiInfo), "`lsgiID`=?", lsgiID)
	if err != nil {
		return 0, err
	}
	if lsgiInfoVals.Len() < 1 {
		return 0, sql.ErrNoRows
	}
	lsgiInfo = lsgiInfoVals.Index(0).Interface().(*worlddb.LootSetGroupItem)
	lsgiInfo.LsgiID = 0
	ID, err := fusion.SaveJsontableToDB(tx, lsgiInfo)
	if err != nil {
		return 0, err
	}
	return ID, nil
}

func copyLootSetGroupChequeInstance(db *sql.DB, tx *sql.Tx, lsgcID uint32) (uint32, error) {
	var lsgcInfo *worlddb.LootSetGroupCheque
	lsgcInfoVals, err := fusion.LoadJsontableFromDB(
		db, reflect.TypeOf(lsgcInfo), "`lsgcID`=?", lsgcID)
	if err != nil {
		return 0, err
	}
	if lsgcInfoVals.Len() < 1 {
		return 0, sql.ErrNoRows
	}
	lsgcInfo = lsgcInfoVals.Index(0).Interface().(*worlddb.LootSetGroupCheque)
	lsgcInfo.LsgcID = 0
	ID, err := fusion.SaveJsontableToDB(tx, lsgcInfo)
	if err != nil {
		return 0, err
	}
	return ID, nil
}

func deleteLootSetInstance(tx *sql.Tx, lsID uint32) error {
	tblNames := []string{
		"loot_set",
		"loot_set_group",
		"loot_set_group_item",
		"loot_set_group_cheque",
	}
	return fusion.RunDBBatchDelete(tx, tblNames, "lsID", lsID)
}

func deleteLootSetGroupInstance(tx *sql.Tx, lsgID uint32) error {
	tblNames := []string{
		"loot_set_group",
		"loot_set_group_item",
		"loot_set_group_cheque",
	}
	return fusion.RunDBBatchDelete(tx, tblNames, "lsgID", lsgID)
}

func deleteLootSetGroupItemInstance(tx *sql.Tx, lsgiID uint32) error {
	tblNames := []string{"loot_set_group_item"}
	return fusion.RunDBBatchDelete(tx, tblNames, "lsgiID", lsgiID)
}

func deleteLootSetGroupChequeInstance(tx *sql.Tx, lsgcID uint32) error {
	tblNames := []string{"loot_set_group_cheque"}
	return fusion.RunDBBatchDelete(tx, tblNames, "lsgcID", lsgcID)
}

func saveLootSetInstance(tx *sql.Tx, lsProto *LootSetPrototype) error {
	_, err := fusion.SaveJsontableToDB(tx, lsProto.LsInfo)
	if err != nil {
		return err
	}
	if lsProto.LsgInfo != nil && lsProto.LsgInfo.LsgID != 0 {
		_, err = fusion.SaveJsontableToDB(tx, lsProto.LsgInfo)
		if err != nil {
			return err
		}
	}
	if lsProto.LsgiInfo != nil && lsProto.LsgiInfo.LsgiID != 0 {
		_, err = fusion.SaveJsontableToDB(tx, lsProto.LsgiInfo)
		if err != nil {
			return err
		}
	}
	if lsProto.LsgcInfo != nil && lsProto.LsgcInfo.LsgcID != 0 {
		_, err = fusion.SaveJsontableToDB(tx, lsProto.LsgcInfo)
		if err != nil {
			return err
		}
	}
	return nil
}
